import asyncio
from typing import TypedDict
class Result(TypedDict):
    rid:int
    body:dict
task_queue:asyncio.Queue[Result]=asyncio.Queue()
sender_on=True
async def submit_task(rid:int,dct:dict):
    global task_queue,sender_on
    if not sender_on: return False
    await task_queue.put({'rid':rid,'body':dct})
    return True
from sjudger.config import RESULT_URLS,RESULT_TIMEOUT
from sjudger.common import NormalResponse,ErrorCode
import aiohttp
import logging as log
async def _send_task(dct:Result):
    if dct['rid']<0: return
    log.debug(f"[SUBMIT] submiting")
    async with aiohttp.ClientSession() as session:
        ok_cnt=0
        for i in RESULT_URLS:
            log.debug(f"[SUBMIT] send to {i}")
            try:
                async with session.post(i,json=dct,timeout=RESULT_TIMEOUT) as response:
                    if response.status!=200:
                        raise ValueError(f"Remote host responding with code {response.status}")
                    resp:NormalResponse=response.json()
                    if resp['error']!=ErrorCode.OK:
                        raise ValueError(f"Remote host responding with error {resp['error']}")
                    ok_cnt+=1
            except Exception as e:
                log.error(f"[SUBMIT] Failed to send result to {i}")
        log.debug(f"[SUBMIT] {ok_cnt}/{len(RESULT_URLS)} succeeded")

async def kill_sender(force=False):
    global sender_on,task_queue
    sender_on=False
    await task_queue.put({'rid':-1,'body':{}}) # put a special task
    log.info("[SENDER] Scheduled exit singnaled")
    if not force:
        log.info("[SENDER] Cleaning uncompleted task")
        while True:
            try:
                dat=task_queue.get_nowait()
            except asyncio.QueueEmpty as e:
                log.info("[SENDER] Cleared")
                break
            _send_task(dat)
            task_queue.task_done()
    else:
        log.warning(f"[SENDER] {task_queue.qsize()} tasks were deprecated due to force=True")
        

async def sender_loop():
    global sender_on,task_queue
    while sender_on:
        dat=await task_queue.get()
        if dat['rid']<0 or not sender_on: # please, send a 
            log.info("[SENDER] Scheduled exit detected")
            if dat['rid']>=0:
                await task_queue.put(dat)
            task_queue.task_done()
            break
        _send_task(dat)
        task_queue.task_done()

